home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / progtool / modula2 / hk_lib / readme.
Encoding:
Text File  |  1994-09-22  |  29.7 KB  |  714 lines

  1.   Z.009: Vorneweg
  2.   Z.028: Inhalt
  3.   Z.186: Assemblerbenutzung
  4.   Z.410: Compiler, Standardprozeduren und Laufzeitsystem
  5.   Z.659: Literatur
  6.   Z.690: Zu guter Letzt
  7.  
  8.  
  9.   Vorneweg:                                                6. März '90
  10.   ======================================================================
  11.  
  12.   HK_LIB_1.0  darf und soll unter folgenden Bedingungen weitergegeben
  13.   werden:
  14.  
  15.         1. Der Ordner HK_LIB_1.0 muß immer vollständig kopiert
  16.            werden, d.h. mit Quelltexten, Objektdateien und diesem
  17.            README.
  18.  
  19.         2. Für die Weitergabe dürfen keine Gebühren verlangt
  20.            werden, außer den üblichen ( manchmal reichlich hohen )
  21.            Kopier- und Diskettenkosten.
  22.  
  23.         3. HK_LIB_1.0 darf nicht ohne meine Genehmigung mit kommer-
  24.            ziellen Produkten weitergegeben oder in kommerziellen
  25.            Produkten verwendet werden.
  26.  
  27.  
  28.   Inhalt:
  29.   ========================================================================
  30.  
  31.   HK_LIB ist eine Sammlung unterschiedlicher Module für das Public-Domain
  32.   Modulasystem 'LPR-Modula'. Mit ein paar kleinen Anpassungen läßt es sich
  33.   wahrscheinlich aber leicht auf andere Modulasysteme übertragen, da sämt-
  34.   liche Quellcodes vorhanden sind.
  35.  
  36.   Auf der Diskette sollten folgende Dateien vorhanden sein:
  37.  
  38.    \HK_LIB_1.0
  39.  
  40.         \DEF_MOD   * Ordner mit den Quelltexten
  41.  
  42.              ASCII   .DEF/MOD
  43.              CHARS   .DEF/MOD
  44.              CONVERTS.DEF/MOD
  45.              LONGSETS.DEF/MOD
  46.              MACHINE .DEF/MOD
  47.              MATHBASE.DEF/MOD
  48.              MEMORY  .DEF/MOD
  49.              QUEUES  .DEF/MOD
  50.              SCREEN  .DEF/MOD
  51.              STACKS  .DEF/MOD
  52.              STRINGS .DEF/MOD
  53.              TIMER   .DEF/MOD
  54.              TRAPDEFS.DEF/MOD
  55.              XSTRINGS.DEF/MOD
  56.  
  57.         \SBM_OBM   * Ordner mit den Objektdateien
  58.  
  59.              ASCII   .SBM/OBM
  60.              CHARS   .SBM/OBM
  61.              CONVERTS.SBM/OBM
  62.              LONGSETS.SBM/OBM
  63.              MACHINE .SBM/OBM
  64.              MATHBASE.SBM/OBM
  65.              MEMORY  .SBM/OBM
  66.              QUEUES  .SBM/OBM
  67.              SCREEN  .SBM/OBM
  68.              STACKS  .SBM/OBM
  69.              STRINGS .SBM/OBM
  70.              TIMER   .SBM/OBM
  71.              TRAPDEFS.SBM/OBM
  72.              XSTRINGS.SBM/OBM
  73.  
  74.         README     * Diese Datei
  75.  
  76.  
  77.   Hier soll nur ein kleiner Überblick gegeben werden, die genaue Beschrei-
  78.   bung der einzelnen Routinen steht in den relativ ausführlich kommentierten
  79.   Definitionsmodulen, im Zweifelsfall hilft sicher auch ein Blick in die
  80.   Implementationsmodule, in deren Kopftexten z.T. ausführliche Erläuterungen
  81.   zu den verwendeten Verfahren zu finden sind.
  82.  
  83.  
  84.   ASCII: --------------------------------------------------------------
  85.      Das ist ein reines Datenmodul mit Konstanten für ASCII-Codes und
  86.      deutsche Sonderzeichen.
  87.  
  88.   Chars: --------------------------------------------------------------
  89.      Hier steht alles, was mit Einzelzeichen zu tun hat, wobei ich
  90.      mich bemüht habe, die deutschen Umlaute weitgehend zu berücksich-
  91.      tigen; so gibt es neben Testroutinen ("IsDigit", "IsUmlaut" usw. )
  92.      auch Konvertierungsfunktionen ("LowerCaseGerman","ToAtariGerman"..).
  93.      Die Funktionen sind teilweise in Assembler programmiert, was aber
  94.      nicht die erhoffte Geschwindigkeitssteigerung gebracht hat.
  95.  
  96.   Strings: ------------------------------------------------------------
  97.      Standardprozeduren für MODULA-Strings, teilweise mit erweiterten
  98.      Parametern. Zusätzlich Routinen für Benutzung von Einzelzeichen
  99.      mit Strings.
  100.      Das Modul ist zum überwiegenden Teil in Assembler geschrieben
  101.      ( die MODULA-Quellen sind allerdings auch noch als Kommentar
  102.      vorhanden ), sodaß die Prozeduren sehr schnell sind ( ich hoffe:
  103.      auch richtig...)
  104.  
  105.   XStrings: -----------------------------------------------------------
  106.      Weitere Prozeduren für Strings, hauptsächlich für die Suche inner-
  107.      halb der Strings auf unterschiedliche Arten.
  108.  
  109.   LongSets: -----------------------------------------------------------
  110.      Hiermit können Mengen mit bis zu 65535 Elementen verwendet werden;
  111.      es sind alle grundlegenden Mengenoperationen vorhanden. Der Element-
  112.      typ und damit die tatsächliche Anzahl der Mengenelemente kann (muß)
  113.      im Definitionsmodul angegeben weden, worauf ein Übersetzungsvor-
  114.      gang erfolgen muß. Voreingestellt ist der Typ CHAR mit 256 Elementen.
  115.  
  116.   Stacks, Queues: -----------------------------------------------------
  117.      Universelle und effiziente Implementierung dieser Datenstrukturen
  118.      mit allen grundlegenden Funktionen. Es können Daten beliebigen Typs
  119.      verarbeitet werden und die Speicherverwaltung kann in Grenzen bei
  120.      der Einrichtung beeinflußt werden. Es ist eine automatische Fehler-
  121.      behandlung möglich.
  122.  
  123.   ConvertStr: ---------------------------------------------------------
  124.      Hier sind Konvertierungen zwischen allen Standarddatentypen von
  125.      MODULA - außer REAL und LONGREAL - und Strings enthalten.
  126.      Es können auch BOOLEAN-, BITSET- und BYTE-Werte verarbeitet werden.
  127.      Die gewünschte Feldbreite und z.T. auch die Zahlenbasis können ange-
  128.      geben werden. Eine automatische Fehlerbehandlung ist möglich.
  129.  
  130.   MathBase: -----------------------------------------------------------
  131.      Prozeduren für gezielten Zugriff auf Exponent und Mantisse von
  132.      REAL- und LONGREAL-Zahlen, unter anderem auch als schnelle Multi-
  133.      plikations- und Divisionsoperationen mit Zweierpotenzen zu gebrau-
  134.      chen. Außerdem:  SIGN, real, entier, round; auch für beide REAL-
  135.      Typen.
  136.  
  137.   Screen: -------------------------------------------------------------
  138.      Prozeduren zur Verwendung der VT52-Terminalemulation des ATARI und
  139.      verschiedene Einstellungsoperationen ( Cursorblinken... ). Unter-
  140.      schiedliche Prozeduren zur Ausgabe von Zeichen und Strings direkt
  141.      aufs Terminal ( mit BIOS.Bconout-RAWCON und CON  ) und umlenkbar
  142.      ( GEMDOS.Cconout und Cconws ).
  143.  
  144.   Timer: --------------------------------------------------------------
  145.      Ermöglicht Zeitmessungen mit 5 ms Auflösung.
  146.  
  147.   MEMORY: -------------------------------------------------------------
  148.      Schnelles Kopieren, Austauschen, Füllen, Löschen und Vergleichen
  149.      von typenlosen Speicherbereichen ( assemblerprogrammiert ).
  150.  
  151.   TRAPdefs: -----------------------------------------------------------
  152.      Datenmodul mit den Trapdefinitionen, die für Betriebssystemaufrufe
  153.      nötig sind. Sämtliche vorkommenden Kombinationen von Parameter-
  154.      größen sind vorhanden.
  155.  
  156.   MACHINE: ------------------------------------------------------------
  157.      Zugriff auf Systemvariablen, Änderung der Interruptpriorität...
  158.      Nur für Spezialisten.
  159.  
  160.  
  161.  
  162.   Einige Module sind voneinander abhängig, d.h. die Übersetzungsreihenfolge
  163.   muß beachtet werden:
  164.  
  165.  
  166.      Chars      Stacks     Queues         MACHINE           Screen
  167.        |          |          |             /   \              |
  168.        V          V          V            V     V             V
  169.      ASCII      MEMORY     MEMORY      MEMORY  TRAPdefs    TRAPdefs
  170.  
  171.  
  172.      ConvertStr         XStrings
  173.          |               /    \
  174.          V              V      V
  175.        Chars         Strings  Chars
  176.          |                      |
  177.          V                      V
  178.        ASCII                  ASCII
  179.  
  180.  
  181.  
  182.   Die Module "LongSets", "Stacks", "Queues" und "ConvertStr" wurden mit
  183.   Testmodus übersetzt, die anderen ohne.
  184.  
  185.  
  186.   Assemblerbenutzung:
  187.   ========================================================================
  188.  
  189.   Hier folgen einige Informationen über die Variablen- und Parameter-
  190.   benutzung auf Assemblerebene, soweit ich das durch eigene Versuche
  191.   ermitteln konnte.
  192.  
  193.   Alle Variablen und Parameter beginnen an einer geraden Adresse, auch
  194.   solche vom Typ CHAR, BOOLEAN oder Aufzählungstypen ( alles BYTE-Größe ).
  195.  
  196.   Die Parameterübergabe findet vollständig über den Stack statt, auch
  197.   Funktionswerte werden nicht in einem Register, sondern auf dem Stack
  198.   zurückgegeben.
  199.   VALUE-Parameter ( außer den weiter unten besprochenen offenen Feldern )
  200.   werden vom Aufrufer komplett auf den Stack kopiert, bei VAR-Parametern
  201.   ists nur die Adresse.
  202.   Die Parameter werden in der Reihenfolge ihres Auftretens in der Liste
  203.   auf dem Stack abgelegt, d.h. der erste in der Liste stehende Parameter
  204.   bzw. seine Adresse wird als erstes auf den Stack gebracht. Ist die
  205.   aufgerufene Prozedur eine Funktion, wird der Platz für die Rückgabe
  206.   des Funktionswertes vor allen Parametern auf dem Stack reserviert
  207.   ( Der Funktionswert ist sozusagen der nullte Parameter ).
  208.  
  209.   Jede Prozedur räumt - neben den lokalen Variablen - ihre eigenen Para-
  210.   meter vom Stack, sodaß der Aufrufer die von ihm abgelegten aktuellen
  211.   Parameter nicht mehr entfernen muß, außer einem evtl. Funktionswert.
  212.  
  213.   Bei Prozedureintritt werden die Register d0-d7 und a0-a3 nicht geret-
  214.   tet; wenn Werte in diesen Registern stehen, die nach dem Aufruf noch
  215.   benötigt werden, müssen sie vom Aufrufer vor dem Aufruf auf dem
  216.   Stack gesichert werden - normalerweise werden aber keine Werte in
  217.   Registern gehalten außer innerhalb von Ausdrücken ( Zwischenwerte ).
  218.  
  219.   Die Register d0-d7,a0-a3 sind für die Verwendung von Assemblerpro-
  220.   grammen frei, solange innerhalb einer Prozedur nicht mit einer Mischung
  221.   aus MODULA- und INLINE-Code gearbeitet wird, ansonsten muß ein Dis-
  222.   assemblerlisting über die Verwendung der Register im MODULA-Code
  223.   Aufschluß geben.
  224.   Die Register a4-a7 werden vom System benötigt und dürfen daher nicht
  225.   verändert werden ( außer a7 als Parameter- und Sicherungsstack ).
  226.  
  227.   Wird eine verschachtelte ( lokale ) Prozedur aufgerufen, wird das
  228.   Register a6 - der Zeiger auf den eigenen lokalen Datenraum - vom
  229.   Aufrufer auf dem Stack abgelegt, sodaß die aufgerufene Prozedur
  230.   Zugriff auf die lokalen Variablen und Parameter des Aufrufers hat.
  231.  
  232.  
  233.   Nach dem BEGIN einer Prozedur sieht der Stack wie folgt aus:
  234.  
  235.  
  236.     -- nur auf diesen Bereich hat die Prozedur direkten Zugriff
  237.    |
  238.    V               ___________________________
  239.    #           -->|                           |<-- erster Parameter
  240.    #          |   |  akt. Parameter           | ^
  241.    #          |   |                           | |
  242.    #          |   |                           | |
  243.    #          +---|---------------------------|<-- letzter Parameter
  244.    #          |   |  RTN-Adresse              |
  245.    #   konst. |   |---------------------------|
  246.    #   Offset |12 |  Modulbasis/ A6-Aufrufer  |
  247.    #          |   |---------------------------|
  248.    #          |   |  altes A6                 |
  249.    #  A6 -----+-->|---------------------------|
  250.    #          |   |                           |<-- erste lokale Variable
  251.    #   neg.   |   |  lokale Variablen         | ^
  252.    #   Offsets|   |                           | |
  253.    #          |   |                           | |
  254.    #           -->|---------------------------|<-- letzte lokale Variable
  255.                   |                           |<-- erster Par. dieses Typs
  256.                   |  VALUE-Parameter vom Typ  | ^
  257.                   |  ARRAY OF ...             | |
  258.                   |                           | |
  259.       A7 -------->|---------------------------|<-- letzter Par. dieses Typs
  260.                   :                           :
  261.                   :  Platz für Proz.aufrufe   :
  262.                   :                           :
  263.                                |
  264.                                |
  265.                                V
  266.                             fallende
  267.                             Adressen
  268.  
  269.  
  270.   Bei offenen Feldparametern ( ARRAY OF Typ ) kann die Größe der
  271.   Parameter erst zur Laufzeit bestimmt werden; vom Aufrufer wird daher
  272.   vor der Adresse des Feldes noch der maximale Index ( HIGH(..) )
  273.   auf den Stack gebracht. Es wird immer nur die Adresse eines offenen
  274.   Feldes übergeben, egal ob es ein VALUE- oder VAR-Parameter ist, im
  275.   Gegensatz zu Parametern aller anderen Typen.
  276.   Ist es ein VALUE-Parameter, so wird das Feld von der aufgerufenen
  277.   Prozedur vor seine lokalen Variablen auf den Stack kopiert, ent-
  278.   sprechend wird die Adresse des nun lokalen Strings im Feld der
  279.   aktuellen Parameter auf den entsprechenden Wert gesetzt; es wird nur
  280.   über diese Adresse im akt.Parameter-Feld auf solche Feldparameter
  281.   zugegriffen.
  282.  
  283.   Als Beispiel folgt hier ein Disassemblerlisting einer Prozedur
  284.   mit einem VALUE-Parameter vom Typ ARRAY OF CHAR:
  285.  
  286.  
  287.         MOVE.L  A4,-(SP)      ; Modulbasis des Aufrufers retten
  288.         MOVEA.L $44(PC),A4    ; a4 -> eigene Modulbasis
  289.         LINK    A6,#-$2       ; Platz für lokale Variable
  290.         MOVE.W  $10(A6),D2    ; d2 := HIGH( string );
  291.  
  292. ; ---------   String in lokale Variable kopieren
  293.  
  294.         ADDQ.W  #$1,D2        ; Länge des Feldes ( = HIGH(..)+1 )
  295.         BTST    #$0,D2        ; ungerade Anzahl ?
  296.         BEQ.S   copy          ; B: nein, ok
  297.         ADDQ.W  #$1,D2        ; ja, gerade machen, damit gerade Adresse
  298. copy:   SUBA.W  D2,SP         ; SP -> lokale Stringvariable
  299.         MOVEA.L $C(A6),A3     ; a3 -> string
  300.         MOVE.L  SP,$C(A6)     ; Adr. des lokalen Strings merken, die Adr.
  301.                               ; des Originalstrings wird nicht mehr gebraucht
  302.         MOVEA.L SP,A2         ; a2 -> lokale Stringvariable
  303.         SUBQ.W  #$1,D2        ; wegen dbra
  304. copylp: MOVE.B  (A3)+,(A2)+   ; String kopieren
  305.         DBRA    D2, copylp    ;
  306.  
  307. ; ---------------------------------------------
  308. ;      Prozedurrumpf
  309. ; ---------------------------------------------
  310.  
  311. procend:UNLK    A6              ; lokale Variablen abbauen
  312.         MOVEA.L (SP)+,A4        ; a4 -> Modulbasis des Aufrufers
  313.         MOVEA.L (SP)+,A0        ; a0 -> RTN-Adr.
  314.         ADDQ.L  #$6,SP          ; Parameter vom Stack entfernen
  315.         JMP     (A0)            ; END  Length;
  316.  
  317.  
  318.        ------------------------------------------
  319.  
  320.  
  321.   SYSTEM exportiert eine Pseudoprozedur zur Einbettung von Assem-
  322.   blercode in den Quelltext: INLINE. Im Gegensatz zu INLINE eignet
  323.   sich die Peudoprozedur CODE, die Teil der Schlüsselworte ist und
  324.   nicht importiert werden darf, dazu, im Modulaprogrammtext Betriebs-
  325.   systemaufrufe oder andere Funtionen, für die man TRAPs braucht,
  326.   abzusetzen ( siehe DEF.Modul Process und TRAPdefs ).
  327.   Hierzu plaziert man ein CODE-Statement direkt unter eine Prozedur-
  328.   deklaration anstelle des Prozedurrumpfes ( gleiche Syntax wie
  329.   das FORWARD-Statement ). Wird diese Prozedur aufgerufen, so
  330.   werden zuerst die entsprechenden Prozedurparameter auf dem Stack
  331.   abgelegt, und dann das 16-Bit-Befehlswort ausgeführt, das vom
  332.   Compiler anstelle des Prozeduraufrufs in den Code eingebettet
  333.   wurde; dieses Befehlswort kann sinnvollerweise nur ein TRAP-Befehl
  334.   sein.
  335.   Mit diesem Befehl lassen sich zum Beispiel die Betriebssystem-
  336.   routinen benutzen.
  337.   Zu beachten ist, daß die Parameter vom Compiler in der Reihenfolge
  338.   ihres Autretens in der Parameterliste auf den Stack gebracht werden,
  339.   d.h. umgekehrt wie bei 'C'-Compilern ( die Funktionsnummer ist also
  340.   der LETZTE Parameter in der Liste ). Da die meisten Beispiele in
  341.   Büchern für Betriebssystemaufrufe in 'C' gehalten sind, müssen die
  342.   angegebenen Parameter in umgekehrter Reihenfolge geschrieben werden.
  343.   Da die Betriebssystemroutinen meistens ihren Funktionswert in Regis-
  344.   ter D0 zurückgeben, muß dieser anschließend noch mit  REG( 0 ) und
  345.   evtl. Typkonvertierung einer Variablen zugewiesen oder als Funktions-
  346.   wert zurückgegeben werden.
  347.  
  348.  
  349.     Beispiel: ( siehe z.B. auch Modul "Screen" )
  350.  
  351.  
  352.       CONST Akku   = 0; (* M68000-Register D0 *)
  353.             Getrez = 4; (* Xbios-Funktionsnr. *)
  354.  
  355.       PROCEDURE getrez():CARDINAL;
  356.  
  357.         PROCEDURE XBIOS (Nr : CARDINAL); CODE(4E4EH); (* XBIOS-Trap *)
  358.  
  359.         BEGIN (* getrez *)
  360.           XBIOS( Getrez );
  361.           RETURN( SHORT( REG( Akku )));
  362.  
  363.           (* wird zu:
  364.            *   move.w  #Getrez, -(sp)
  365.            *   trap    #XBIOS
  366.            *   move.w  d0, RETURN(a6)
  367.            *)
  368.         END getrez;
  369.  
  370.   Vorsicht ist geboten, falls der Aufruf einer solchen Prozedur in einer
  371.   Schleife geschieht: da der Stack nicht automatisch korrigiert wird
  372.   ( Parameter entfernen ), wächst er immer weiter an...
  373.   Bei einem einmaligen Aufruf macht das nichts, da bei Prozedurende
  374.   der bei Prozedureintritt gesicherte ( LINK ... ) Stackpointer
  375.   wieder zurückgeschrieben wird ( UNLK ... ), und somit sämtliche
  376.   eventuell auf dem Stack noch liegenden Werte wieder entfernt werden.
  377.   ( Bei einem wiederholten Aufruf innerhalb der Prozedur wird der Stack
  378.   am Ende der Prozedur natürlich auch wieder bereinigt, aber wenn z.B.
  379.   in einer Schleife 1000-mal Parameter von vielleicht 20 Bytes auf dem
  380.   Stack abgelegt werden, wächst womöglich der Stack in andere Speicher-
  381.   bereiche hinein - einen Stacktest gibt es bei diesem Compiler ja leider
  382.   nicht ):
  383.  
  384.        ------------------------------------------
  385.  
  386.   Bei eingeschaltetem Testmodus produziert der Compiler zusätzlichen Code
  387.   zur Überprüfung von Index- und Bereichsüberschreitungen ( auch bei Unter-
  388.   bereichstypen! ) und fehlenden RETURN-Anweisungen bei Funktionsprozeduren.
  389.   Da der Compiler den Assemblercode nicht entschlüsseln kann, fügt er na-
  390.   türlich auch keinen Code für die Index- oder Bereichsüberschreitung ein;
  391.   am Ende einer Funktionsprozedur prozedur werden allerdings immer ein paar
  392.   Bytes eingefügt, die einen Laufzeitfehler produzieren ( -> 'Funktionspro-
  393.   zedur ohne RETURN'). Durch eine explizite RETURN-Anweisung wird dieser
  394.   Code durch einen Sprungbefehl im wahrsten Sinne des Wortes umgangen.
  395.   Codiert man nun in Assembler eine Funktionsprozedur, so muß entweder
  396.   ein zusätzlicher Sprungbefehl eingebaut werden, was aber nicht so einfach
  397.   ist, da das Sprungziel per INLINE nicht erreichbar ist - es liegt prak-
  398.   tisch innerhalb der END-Anweisung, die zweite Möglichkeit wäre, den
  399.   Funktionswert durch
  400.  
  401.         RETURN( VAL( Funtionstyp, REG( Register )))
  402.  
  403.   zurückzugeben. Schließlich kann man auch den Testmodus ausschalten, was
  404.   nicht weiter tragisch ist, da in den Assemblercode sowieso keine weiteren
  405.   Tests eingebaut werden ( können ). Hat man sowohl MODULA-Quelltext als
  406.   auch INLINEs im Modul, sollten die MODULA-Teile unbedingt vorher MIT Test-
  407.   modus ausgetestet werden.
  408.  
  409.  
  410.   Compiler, Standardprozeduren und Laufzeitsystem
  411.   ====================================================================
  412.  
  413.   Hier folgen einige Eigenheiten der oben angegebenen Komponenten.
  414.  
  415.  
  416.   Das Pseudomodul 'SYSTEM' exportiert eine Funktion 'SHIFT':
  417.  
  418.       stdtyp1 := SHIFT( stdtyp2, shift );
  419.  
  420.   Für 'stdtyp' kann ein beliebiger Standarddatentyp oder ein Unterbereichs-
  421.   typ außer REAL oder LONGREAL stehen. Die Funktion weist der Variablen
  422.   'stdtyp1' den um <shift> Bits nach rechts oder links verschobenen
  423.   Wert von 'stdtyp2' zu.
  424.  
  425.      shift < 0 : um <shift> Bits nach rechts schieben
  426.      shift > 0 :          -"-         links     "
  427.  
  428.   <shift> wird MODULO 32 behandelt, d.h <shift> = 33 äq. <shift> = 1.
  429.   Ist 'stdtyp2' vom Typ INTEGER, LONGINT oder ein Unterbereich vom
  430.   Typ INTEGER, wird arithmetisch verschoben, sonst logisch.
  431.  
  432.   Beispiele für die Umsetzung des SHIFT-Befehls in Assemblercode:
  433.  
  434.            :
  435.  
  436.      VAR  bs : BITSET;
  437.           li : LONGINT;
  438.  
  439.            :
  440.  
  441.      bs := SHIFT( bs, 13 );
  442.  
  443.         (* wird zu:
  444.          *    move.w bs(a6), d2
  445.          *    lsl.w  #5, d2
  446.          *    lsl.w  #8, d2
  447.          *    move.w d2, bs(a6)
  448.          *)
  449.  
  450.      li := SHIFT( li, -5 );
  451.  
  452.         (* wird zu
  453.          *    move.l li(a6), d2
  454.          *    asr.l  #-5, d2
  455.          *    move.l d2, li(a6)
  456.          *)
  457.  
  458.   Das funktioniert auch, wenn <shift> eine Variable ist; diese wird immer
  459.   als Zahl mit Vorzeichen interpretiert, sodaß zur Laufzeit entschieden
  460.   wird, in welche Richtung zu schieben ist.
  461.  
  462.        ------------------------------------------
  463.  
  464.   Folgende Standardprozeduren arbeiten mit INTEGER- statt der erwarteten
  465.   CARDINAL-Werte
  466.  
  467.      ABS   !!
  468.      HIGH
  469.      ORD
  470.      LONG     * bei Anwendung auf CARDINAL
  471.      SHORT    *        -"-        LONGCARD
  472.      TRUNC
  473.      TRUNCD
  474.      FLOAT
  475.      FLOATD
  476.  
  477.   Wobei mit 'arbeiten' der zur Uebersetzungszeit bekannte Funktionstyp
  478.   gemeint ist ( Meldung: 'incompatible Operand Types' ); was dann zur
  479.   Laufzeit produziert wird, ist manchmal etwas ganz anderes!
  480.  
  481.   Beispiel:
  482.  
  483.     card := SHORT( longcard );
  484.  
  485.     Ist der Testmodus eingeschaltet, wird überprüft, ob der Wert
  486.     MAX(INTEGER) überschritten wird - d.h. SHORT soll nur INTEGER-
  487.     Werte produzieren.
  488.  
  489.     longcard := LONG( card );
  490.  
  491.     Hier wird <card> vor der Zuweisung auf LONGCARD erweitert ( das
  492.     höherwertige Wort wird gelöscht ), und auch bei eingeschaltetem
  493.     Testmodus findet keine weitere Ueberprüfung statt, d.h. LONG
  494.     liefert LONGCARD-Werte, obwohl der Compiler LONG als LONGINT-
  495.     Funktion betrachtet ( longcard := longcard + LONG( card ); produ-
  496.     ziert den Typfehler )!
  497.  
  498.  
  499.   Wohl am Laufzeitmodul 'System' liegt es, daß FLOAT vom Compiler her auch
  500.   negative Werte akzeptiert ( FLOAT und TRUNC werden in Aufrufe von
  501.   System.FLOATs bzw. System.TRUNCs umgesetzt, TRUNCD und FLOATD in
  502.   System.TRUNCd und System.FLOATd ) aber daraus Unsinn produziert;
  503.   FLOATD hingegen verarbeitet auch negative Zahlen korrekt.
  504.  
  505.   Die Systemroutinen für TRUNC und FLOAT arbeiten übrigens, wie man aus
  506.   dem Definitionsmodul ersehen kann, mit LONGINT-Parametern; hier entsteht
  507.   ein neues Problem: Die automatische Längenanpassung bei Zuweisung und
  508.   Übergabe als Value-Parameter:
  509.  
  510.   Bei der automatischen Anpassung der Längen von INTEGER und CARDINAL- auf
  511.   LONG-Zahlen ist Vorsicht angebracht: Soll z.B. der Absolutwert einer
  512.   INTEGER-Zahl einer LONGCARD-Zahl zugewiesen werden, könnte man schreiben:
  513.  
  514.       lc := ABS( int );
  515.  
  516.   Ist aber <int> = MIN(INTEGER), so wird der Wert durch ABS() nicht
  517.   geändert, da es für diesen Wert keine entsprechende positive Zahl im
  518.   Zweierkomplement gibt; was passiert? MIN(INTEGER) wird für die Zuweisung
  519.   vorzeichenrichtig auf LONGINT erweitert, als Kardinalzahl interpretiert
  520.   ist das aber MAX(LONGCARD) - MAX(INTEGER), und nicht etwa
  521.   MAX(INTEGER) + 1, wie erwartet.
  522.  
  523.   Abhilfe:
  524.  
  525.       lc := ABS( LONG( int ));
  526.  
  527.   Da hier zuerst auf LONGINT erweitert wird und dann der Absolutwert genom-
  528.   men wird, kann der Wertebereich nicht überschritten werden.
  529.  
  530.  
  531.   Bei der Konvertierung von CARDINAL- und INTEGER-Zahlen und bei der Benut-
  532.   zung von Standardprozeduren ist also Wachsamkeit angesagt - hier hilft
  533.   oft nur Probieren.
  534.  
  535.         -------------------------------------------------
  536.  
  537.   Ach ja, das Laufzeitmodul: Die Division von LONGREAL-Zahlen wird, falls
  538.   nicht gerade durch eine Zweierpotenz dividiert werden soll, durch einen
  539.   Fehler mit schätzungsweise 32 statt 53 BIT Genauigkeit ausgeführt!
  540.   Da unter anderem wohl auch der Compiler mit diesem Laufzeitmodul über-
  541.   setzt wurde, lassen sich auch LONGREAL-Konstanten im Programmtext
  542.   ( 1.23456789D bzw. 1.23456789D00 ) nur mit dieser Genauigkeit
  543.   - ca. 10 Dezimalstellen - angeben, da bei der Umwandlung der Zeichen-
  544.   ketten auch die Division benötigt wird.
  545.  
  546.   Aber auch bei der Behandlung von REAL-Konstanten kommt der Compiler
  547.   ins Stolpern:
  548.  
  549.     real := 3.9999998   gibt  den angegeben Wert, aber
  550.     real := 3.9999999   gibt  6.0 !!!
  551.  
  552.   Da scheint wohl das Runden nicht so ganz zu funktionieren...
  553.  
  554.  
  555.         -------------------------------------------------
  556.  
  557.   Bei Anwendung der Standardprozedur SIZE auf einen Parameter vom Typ
  558.   ARRAY OF ... passiert recht merkwürdiges. Normalerweise wird die
  559.   Prozedur ja nur dazu benutzt, die Speichergröße von Typen oder Varia-
  560.   blen zu bestimmen, die bereits zur Übersetzungszeit bekannt sind
  561.   ( vom Compiler wird dann nur eine Konstante eingesetzt ); wird sie
  562.   aber z.B. innerhalb einer Prozedur auf einen Parameter vom Typ
  563.   ARRAY OF CHAR angewendet:
  564.  
  565.     card := SIZE( string ); ,
  566.  
  567.   gibt es während des Übersetzens zunächst einen Busfehler! Nun ist ein
  568.   Busfehler in einem Compiler eigentlich schon recht merkwürdig, wird aber
  569.   die Meldung ignoriert und einfach CR gedrückt, so kann man sich nachher
  570.   mittels Disassembler davon überzeugen, daß korrekter Code erzeugt wurde,
  571.   nämlich der für:
  572.  
  573.     card := HIGH( string ) + 1;
  574.  
  575.         ----------------------------------------------
  576.  
  577.   Werden Stringvariablen mit einer ungeraden Anzahl Zeichen deklariert,
  578.   z.B.:
  579.  
  580.     string := ARRAY [0..8] OF CHAR; ,
  581.  
  582.   so kann man diesen Strings auf der Ebene, in der sie deklariert wurden,
  583.   um ein Zeichen längere Stringkonstanten zuweisen, ohne daß der Compiler
  584.   meckert; die Funktion HIGH() liefert dagegen den richtigen Maximalindex.
  585.   Verwirrung kann es schaffen, wenn im Hauptprogramm der Stringvariablen
  586.   ein ( um ein Zeichen zu langer ) Text zugewiesen wurde, und diese Vari-
  587.   able einer Prozedur als Parameter dient; dann bearbeitet die Prozedur
  588.   den String nämlich bis zu dem mit HIGH() festgestellten - korrekten -
  589.   Maximalindex, und das letzte Zeichen fehlt plötzlich, z.B. bei einer
  590.   Ausgabe.
  591.  
  592.       -----------------------------------------------
  593.  
  594.   In der Importliste scheint der Compiler bei den Modulnamen nicht
  595.   zwischen Groß- und Kleinbuchstaben zu unterscheiden, außer bei SYSTEM.
  596.  
  597.       -----------------------------------------------
  598.  
  599.   Während ein Programm unter Kontrolle des Laders läuft, leitet dessen
  600.   Laufzeitsystem einige Exceptions auf eigene Prozeduren um, nach Beendi-
  601.   gung des Laders werden die alten Adressen wiederhergestellt.
  602.   Was bei Exceptions wie Adressfehler, Busfehler usw. ganz praktisch ist,
  603.   erweist sich bei zumindest einer anderen Umlenkung als fatal: Der Trap
  604.   Nr. 11 wird - vom Compiler in den Code eingebettet - dazu verwendet, in
  605.   den Supervisormodus zu schalten. Das wird immer dann benötigt, wenn eine
  606.   Modulpriorität angegeben wird, z.B.:
  607.  
  608.     IMPLEMENTATION MODULE  Spezial[7];
  609.  
  610.   in diesem Fall wird nämlich bei jeglicher dynamischer Benutzung des
  611.   Moduls, also Modulinitialisierung und Prozeduraufrufe, die Interruptebene
  612.   der CPU auf den angegebenen Prioritätswert gesetzt - und dazu wird der
  613.   Supervisormodus gebraucht.
  614.   Eine Priorität ist z.B. beim mitgelieferten 'Process'.Modul angegeben.
  615.   Wird aber nun durch den Linker ein selbständig lauffähiges Programm er-
  616.   zeugt, setzt das Laufzeitsystem des Laders den Vektor für Trap #11 natür-
  617.   lich nicht auf die Routine zur Umschaltung des Modus um. Da der Trap aber
  618.   im Code steht, stürzt das Programm wegen Privilegverletzung ab, sobald
  619.   der Initialisierungsteil eines solchen Moduls bei Programmstart ausge-
  620.   führt wird.
  621.   Abhilfe wäre ein kurzes Modul, das als erstes in jedes Programm impor-
  622.   tiert wird, welches ein anderes Modul mit Prioritätsangabe direkt oder
  623.   indirekt benutzt; in dessen Initialisierungsteil müßte ein kurzes
  624.   Codestück stehen, das den Trap #11-Vektor auf eine dort stehende Pro-
  625.   zedur umsetzt, die den Modus wechselt. Außerdem müßte dieses Modul eine
  626.   Prozedur exportieren, die - bei Programmende aufgerufen - den alten
  627.   Wert des Vektors wieder restauriert.
  628.   Solange der Lader die Kontrolle über das System hat, führt der Vektor
  629.   auf folgende kleine Routine ( disassembliert ):
  630.  
  631.  
  632.     TOSUPER:
  633.       move.w  #$2700, SR        ; Keinen IR während der Aktion zulassen
  634.       ori.w   #$2700, (SP)      ; nach dem Trap auch durch nichts mehr
  635.                                 ; unterbrechbar und im Supervisormodus
  636.       rte                       ; Rückkehr zum Aufrufer
  637.  
  638.  
  639.   Für den Code bei Modulen mit Priorität wird im übrigen der Befehl
  640.  
  641.     move  SR, d*
  642.  
  643.   im Usermodus benutzt; das geht nur beim 68000, sitzt im ATARI ein
  644.   68010/68020, gibt das eine Privilegverletzung; Mit diesen Prozessoren
  645.   kann also beim gegebenen Compiler die Prioritätsangabe nicht verwendet
  646.   werden.
  647.  
  648.   Vom Modul 'Process' werden zusätzlich noch die Traps 3 und 4 auf eigene
  649.   Routinen gelenkt; das geschieht jedoch, wie man sich durch einen Blick
  650.   in den bei der ersten Version von 'LPR-Modula' mitgelieferten Quelltext
  651.   überzeugen kann, ohne Rücksicht auf das, was vorher in den Vektoren
  652.   drinstand; mithin lassen sich die ursprunglichen Werte auch nicht mehr
  653.   restaurieren. Das ist zwar in der Praxis nicht weiter schlimm, da die
  654.   von TOS nicht benutzten Traps wohl auch von anderen Programmen nicht
  655.   verwendet werden, aber auszuschließen ist das auch nicht.
  656.  
  657.  
  658.  
  659.   Literatur:
  660.   =========================================================================
  661.  
  662.   MODULA-2 - Software Components, JOHN WILEY & SONS
  663.  
  664.      Richard F. Sincovec
  665.      Richard S. Wiener
  666.  
  667.  
  668.  
  669.   MODULA-2 - A Software Development Approach, JOHN WILEY & SONS
  670.  
  671.      Gary A. Ford
  672.      Richard S. Wiener
  673.  
  674.  
  675.  
  676.   Algorithmen und Datenstrukturen mit Modula-2, B.G. Teubner
  677.  
  678.      Niklaus Wirth
  679.  
  680.  
  681.  
  682.   ATARI ST Profibuch, SYBEX
  683.  
  684.      Hans-Dieter Jankowski
  685.      Julian F. Reschke
  686.      Dietmar Rabich
  687.  
  688.  
  689.  
  690.   Zu guter Letzt:
  691.   ========================================================================
  692.  
  693.   HK_LIB soll weiterentwickelt werden, da ich aber dummerweise auch
  694.   noch studieren muß, kann es einige Zeit dauern, bis eine neue
  695.   Version erscheint, entsprechende Anfragen sind daher zwecklos.
  696.   Sobald der Umfang der Aenderungen oder Erweiterungen es recht-
  697.   fertigt, wird eine neue Version veröffentlicht.
  698.  
  699.   Ich habe alle Prozeduren getestet; da mir dabei aber sicher diverse
  700.   Grenzfälle entgangen sind, was besonders bei den Assemblerversionen
  701.   leicht passiert, lehne ich jede Verantwortung für Bömbchen, ge-
  702.   löschte Hauptspeicher, in denen vorher die noch nicht gesicherte
  703.   Diplomarbeit stand, formatierte Festplatten usw. ab.
  704.  
  705.   Wenn jemand meint einen Fehler entdeckt zu haben, so kann er/sie/es
  706.   mir ja mal schreiben ( am besten mit Beispiel ).
  707.  
  708.   Meine Adresse ist:
  709.  
  710.                         Holger Kleinschmidt
  711.                         Promenadenstr. 11 b
  712.                         1000 Berlin 45
  713.  
  714.